package plodsoft.mygvm.testruntime

import plodsoft.mygvm.TestingInputStream
import plodsoft.mygvm.file.DefaultFileSystem
import plodsoft.mygvm.memory.DefaultRamModel
import plodsoft.mygvm.model.TestingKeyboardModel
import plodsoft.mygvm.model.TestingScreenModel
import plodsoft.mygvm.model.TestingTextModel
import plodsoft.mygvm.test
import java.io.ByteArrayOutputStream


fun testRuntime() {
    val ram = DefaultRamModel()
    val input = TestingInputStream()
    val output = ByteArrayOutputStream()
    val runtime = plodsoft.mygvm.runtime.Runtime(ram, TestingScreenModel(output), TestingTextModel(output), TestingKeyboardModel(input, output), DefaultFileSystem("."))

    /**
    void main() {
    long a;
    int b;
    char c;
    a = "what";
    b = 1001;
    c = 64;
    printf("hello, %c, %d, %s.<=%s->%%.", c, b, a, "yes");
    }
     */
    runtime.test("printf", input, output, intArrayOf(
            0x4C, 0x41, 0x56, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x3C, 0x00, 0x20, 0x3B, 0x17, 0x00, 0x00,
            0x3E, 0x0C, 0x00, 0x00,
            0x03, 0x05, 0x00, 0x84, 0x00, 0x0D, 0x77, 0x68, 0x61, 0x74, 0x00, 0x35, 0x38,
            0x03, 0x09, 0x00, 0x82, 0x00, 0x02, 0xE9, 0x03, 0x35, 0x38,
            0x03, 0x0B, 0x00, 0x81, 0x00, 0x01, 0x40, 0x35, 0x38,
            0x0D, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x25, 0x63, 0x2C, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x73,
            0x2E, 0x3C, 0x3D, 0x25, 0x73, 0x2D, 0x3E, 0x25, 0x25, 0x2E, 0x00,
            0x0E, 0x0B, 0x00, 0x0F, 0x09, 0x00, 0x10, 0x05, 0x00, 0x0D, 0x79, 0x65, 0x73, 0x00, 0x01, 0x05, 0x82, 0x40),
            "",
            """[add bytes (hello, @, 1001, what.<=yes->%.)]
              |[render text to screen: 0b0]
              |""".trimMargin())

    /**
    void main() {
        printf("%c, %d, %d, %d", 65, 130, (int16) 32768, -2147483647);
    }
     */
    runtime.test("signed number", input, output, intArrayOf(
            0x4C, 0x41, 0x56, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x3C, 0x00, 0x20, 0x3B, 0x17, 0x00, 0x00,
            0x3E, 0x05, 0x00, 0x00,
            0x0D, 0x25, 0x63, 0x2C, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x64, 0x00,
            0x01, 0x41, 0x01, 0x82, 0x02, 0x00, 0x80, 0x03, 0x01, 0x00, 0x00, 0x80, 0x01, 0x05, 0x82, 0x40),
            "",
            """[add bytes (A, 130, -32768, -2147483647)]
              |[render text to screen: 0b0]
              |""".trimMargin())

    /**
    long fact(long n) {
        if (n < 1) {
            return 1;
        } else {
            return n * fact(n - 1);
        }
    }

    void main() {
        printf("%d,%d", fact(1), fact(5));
    }
     */
    runtime.test("fact", input, output, intArrayOf(
            0x4C, 0x41, 0x56, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x3C, 0x00, 0x20, 0x3B, 0x3F, 0x00, 0x00,
            0x3E, 0x09, 0x00, 0x01,
            0x10, 0x05, 0x00, 0x4F, 0x01, 0x00, 0x38, 0x39, 0x2D, 0x00, 0x00, 0x01, 0x01, 0x3F, 0x3B, 0x3C, 0x00, 0x00, 0x10, 0x05, 0x00, 0x10, 0x05, 0x00, 0x46, 0x01, 0x00, 0x3D, 0x17, 0x00, 0x00, 0x2A, 0x3F, 0x01, 0x00, 0x3F,
            0x3E, 0x05, 0x00, 0x00,
            0x0D, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x00, 0x01, 0x01, 0x3D, 0x17, 0x00, 0x00, 0x01, 0x05, 0x3D, 0x17, 0x00, 0x00, 0x01, 0x03, 0x82, 0x40),
            "",
            """[add bytes (1,120)]
              |[render text to screen: 0b0]
              |""".trimMargin())
}

fun main(args: Array<String>) {
    testRuntime()
    println("done")
}